#include <linux/module.h>

#include <linux/compat.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/vt.h>
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/console.h>
#include <linux/kmod.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/efi.h>
#include <linux/fb.h>

#include <asm/fb.h>


static struct fb_ops s3c_lcdfb_ops = {
	.owner		= THIS_MODULE,
//	.fb_setcolreg	= atmel_lcdfb_setcolreg,
	.fb_fillrect	= cfb_fillrect,
	.fb_copyarea	= cfb_copyarea,
	.fb_imageblit	= cfb_imageblit,
};


static struct fb_info *s3c_lcd;

static volatile unsigned long *gpicon;
static volatile unsigned long *gpipud;
static volatile unsigned long *gpjcon;
static volatile unsigned long *gpjpud;
static volatile unsigned long *gpecon;
static volatile unsigned long *gpedat;
static volatile unsigned long *gpfcon;
static volatile unsigned long *gpfdat;

static int lcd_init(void)
{
	s3c_lcd = framebuffer_alloc(0, NULL);

	//setup fix
	strcpy(s3c_lcd->fix.id, "mylcd"); /* identification string eg "TT Builtin" */
	s3c_lcd->fix.smem_len = 480 * 272 * 4; /* Start of frame buffer mem */
	s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS; /* see FB_TYPE_*        */
	s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR;/* TFT */
	s3c_lcd->fix.line_length = 480 * 3;

	//setup var
	s3c_lcd->var.xres = 480;
	s3c_lcd->var.yres = 272;
	s3c_lcd->var.xres_virtual = 480;
	s3c_lcd->var.yres_virtual = 272;

	s3c_lcd->var.bits_per_pixel = 24;

	/* RGB:888 */

	s3c_lcd->var.red.offset     = 16;
	s3c_lcd->var.red.length     = 8;
	
	s3c_lcd->var.green.offset   = 8;
	s3c_lcd->var.green.length   = 8;

	s3c_lcd->var.blue.offset    = 0;
	s3c_lcd->var.blue.length    = 8;

	s3c_lcd->var.activate       = FB_ACTIVATE_NOW;

	//setup operation function
	s3c_lcd->fbops              = &s3c_lcdfb_ops;
	/* 2.4 其他的设置 */
	//s3c_lcd->pseudo_palette =; //
	//s3c_lcd->screen_base  = ;  /* 显存的虚拟地址 */ 
	s3c_lcd->screen_size   = 480*272*24/8;					

	/* 3. 硬件相关的操作 */
	/* 3.1 配置GPIO用于LCD */
	/* 3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等 */
	/* 3.3 分配显存(framebuffer), 并把地址告诉LCD控制器 */
	//s3c_lcd->fix.smem_start = xxx;  /* 显存的物理地址 */
	gpicon = ioremap(0x7f008100, 4);
	gpipud = ioremap(0x7f008108, 4);
	gpjcon = ioremap(0x7f008120, 4);
	gpjpud = ioremap(0x7f008128, 4);
	gpecon = ioremap(0x7f008080, 4);
	gpedat = ioremap(0x7f008084, 4);
	gpfcon = ioremap(0x7f0080a0, 4);
	gpfdat = ioremap(0x7f0080a4, 4);
	
    gpicon = 0xaaaaaaaa;
    gpipud = 0xaaaaaaaa;
    gpjcon = 0xaaaaaa;
    gpjpud = 0xaaaaaa;
	//lcd_pwren on
	gpecon = gpecon & ~0xf | 0x01;
	gpedat |= 0x01;

	//backlight on
	gpfcon = gpfcon & ~(3 << 28) | 1 << 28;
	gpfdat |= 1 << 14; 
	
	register_framebuffer(s3c_lcd);

	return 0;
}

static void lcd_exit(void)
{

}

module_init(lcd_init);
module_exit(lcd_exit);

MODULE_LICENSE("GPL");
